package org.nanotek.lucene.index.search;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiFields;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.Terms;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MMapDirectory;
import org.apache.lucene.store.NIOFSDirectory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.nanotek.cms.domain.lucene.FieldStat;
import org.nanotek.cms.domain.lucene.Index;
import org.nanotek.cms.domain.lucene.TermStats;
import org.nanotek.lucene.SearcherProvider;
import org.nanotek.lucene.SearcherProviderException;

public class IndexSearcherProvider implements SearcherProvider {

	ExecutorService executorService = null;

	public IndexSearcherProvider (){}

	public IndexSearcherProvider(ExecutorService executorService)
	{
		this.executorService = executorService;
	}

	public IndexSearcher getIndexSearcher(Index index)
	{
		return getIndexSearcher(index, executorService);
	}

	public ExecutorService getExecutorService() {
		return executorService;
	}

	public void setExecutorService(ExecutorService executorService) {
		this.executorService = executorService;
	}
	
	public IndexSearcher getIndexSearcher(final Index index, final ExecutorService executorService) {

		IndexSearcher indexSearcher = null;
		try {
			if (index !=null) {
				IndexReader indexReader = null;
				Directory directory = null;
				File file = null;
				IndexType type = index.getIndexType();
				if (type == null) {
					type = IndexType.NMAPDIRECTORY;
					file = new File(index.getIndexAlias());
				} else {
					file = new File(index.getLocation().getHref());
				}

				switch (type){
				case NIOFSDIRECTORY:
					directory = new NIOFSDirectory(file);
					break;
				case SIMPLEFS:
					directory = new SimpleFSDirectory(file);
					break;
				case NMAPDIRECTORY:
					directory = new MMapDirectory(file);
					break;
				default:
					directory = new SimpleFSDirectory(file);
				}
				//TODO : INDEX-CACHE: Analyze to create a cache from index readers....
				if (directory !=null) {
					indexReader = DirectoryReader.open(directory);
					if (executorService !=null) {
						indexSearcher = new IndexSearcher(indexReader , executorService);
					}else {
						indexSearcher = new IndexSearcher (indexReader);
					}
				}
			}
		}  catch (IOException e){
			throw new SearcherProviderException(e);
		}
		return indexSearcher;
	}

	public List<TermStats> getTermStats(Index index, List<Term> termList) {
		IndexSearcher searcher = getIndexSearcher(index, executorService);
		IndexReader reader = searcher.getIndexReader();
		List<TermStats> termStats = new ArrayList<>();
		try {
			for (Term term : termList){
				TermStats termStat = new TermStats();
				Integer termFrequency = reader.docFreq(term);
				Long totalTermFrequency = reader.totalTermFreq(term);
				termStat.setIndex(index);
				termStat.setTerm(term);
				termStat.setTotalTermFrequency(totalTermFrequency);
				termStat.setTermFrequency(termFrequency);
				termStats.add(termStat);
			}
		}catch (IOException e){
			throw new SearcherProviderException(e);
		}
		return termStats;
	}

	public FieldStat getFieldStat(Index index, String field){
		FieldStat fieldStat = new FieldStat();
		IndexSearcher indexSearcher = this.getIndexSearcher(index);
		IndexReader indexReader = indexSearcher.getIndexReader();
		try {
			Terms terms = MultiFields.getTerms(indexReader, field);
			fieldStat.setFieldName(field);
			fieldStat.setDocCount((long) terms.getDocCount());
			fieldStat.setDocFrequency(terms.getSumDocFreq());
			fieldStat.setSumTotalTermFreq(terms.getSumTotalTermFreq());
			fieldStat.setHasOffsets(terms.hasOffsets());
			fieldStat.setHasPositions(terms.hasPositions());
			fieldStat.setHasPayloads(terms.hasPayloads());
		}catch (IOException e){
			throw new SearcherProviderException(e);
		}
		return fieldStat;
	}

}
